﻿//  --------------------------------
//  Copyright (c) AW Systems, Inc. All rights reserved.
//  This source code is made available under the terms of the Microsoft Public License (Ms-PL)
//  http://www.codeplex.com/SLAM/license
//  ---------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Data.Linq;
using System.Data.Common;
using System.Data.SqlClient;
using System.Text;
using System.Text.RegularExpressions;
using Slam.Configuration;

namespace Slam.Data
{
    internal class SqlLogDataRepository : IDisposable
    {
        #region Private State

        private DataContext _dataContext;
        private static List<string> _verifiedTableList = new List<string>();
        private static bool _databaseCreated;
        private string _connectionString;

        #endregion

        #region Constructors and Destructors

        public SqlLogDataRepository(string connectionString)
        {
            _connectionString = connectionString;
        }

        ~SqlLogDataRepository()
        {
            _dataContext.Dispose();
        }

        #endregion

        public void CreateMessageTable(string tableSchema)
        {
            _dataContext = new DataContext(_connectionString);
            _dataContext.ExecuteCommand(SlamItemContext.CommitActivity, String.Format(Queries.CreateMessageLogTable, tableSchema));
        }

        public void CreateEventTable(string tableSchema)
        {
            _dataContext = new DataContext(_connectionString);
            _dataContext.ExecuteCommand(SlamItemContext.CommitActivity, String.Format(Queries.CreateEventLogTable, tableSchema));
        }

        public void CreateSchema(string schemaName)
        {
            _dataContext = new DataContext(_connectionString);
            _dataContext.ExecuteCommand(SlamItemContext.CommitActivity, String.Format(Queries.CreateSchema, schemaName));
        }

        public void LogMessage(string tableSchema, string messageType, string message)
        {
            _dataContext = new DataContext(_connectionString);
            string valueString = String.Format("convert(datetime, '{0}', 101), '{1}', '{2}'", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss.fff"), messageType, message.Replace("'", "''"));
            try
            {
                _dataContext.ExecuteCommand(SlamItemContext.CommitActivity, String.Format(Queries.InsertLogItem, tableSchema, "MessageLog", valueString));
            }
            catch (Exception ex)
            {
                throw new Exception("Logging error: " + String.Format(Queries.InsertLogItem, tableSchema, "MessageLog", valueString) + Environment.NewLine + ex.ToString());
            }
        }

        public void LogEvent(string tableSchema, string eventName, string typeName, string message)
        {
            _dataContext = new DataContext(_connectionString);
            string valueString = String.Format("convert(datetime, '{0}', 101), '{1}', '{2}', '{3}'", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss"), eventName, typeName.Replace("'", "''"), message.Replace("'", "''"));

            try 
            {
                _dataContext.ExecuteCommand(SlamItemContext.CommitActivity, String.Format(Queries.InsertLogItem, tableSchema, "EventLog", valueString));
            }
            catch (Exception ex)
            {
                throw new Exception("Logging error: " + String.Format(Queries.InsertLogItem, tableSchema, "EventLog", valueString) + Environment.NewLine + ex.ToString());
            }
        }

        public void EnsureDatabaseExists()
        {
            _dataContext = new DataContext(_connectionString);
            if (!_databaseCreated && !_dataContext.DatabaseExists())
            {
                throw new DataException("Database does not exist.");
                //_dataContext.CreateDatabase();
            }

            _databaseCreated = true;
        }

        public bool VerifyEventTableExists(string tableSchema)
        {
            _dataContext = new DataContext(_connectionString);
            string tableName = "EventLog";
            EnsureDatabaseExists();
            bool exists = false;
            if (_verifiedTableList.Contains(_connectionString + tableName))
            {
                exists = true;
            }
            else
            {
                exists = _dataContext.ExecuteQuery<int>(SlamItemContext.CommitActivity, String.Format(Queries.VerifyTableExists, tableSchema, tableName)).SingleOrDefault() > 0;
                if (exists)
                {
                    _verifiedTableList.Add(_connectionString + tableName);
                }
            }
            
            return exists;
        }

        public bool VerifyMessageTableExists(string tableSchema)
        {
            _dataContext = new DataContext(_connectionString);
            string tableName = "MessageLog";
            EnsureDatabaseExists();
            bool exists = false;
            if (_verifiedTableList.Contains(_connectionString + tableName))
            {
                exists = true;
            }
            else
            {
                exists = _dataContext.ExecuteQuery<int>(SlamItemContext.CommitActivity, String.Format(Queries.VerifyTableExists, tableSchema, tableName)).SingleOrDefault() > 0;
                if (exists)
                {
                    _verifiedTableList.Add(_connectionString + tableName);
                }
            }
            
            return exists;
        }

        public bool VerifySchemaExists(string schemaName)
        {
            _dataContext = new DataContext(_connectionString);
            EnsureDatabaseExists();
            bool exists = false;
            exists = _dataContext.ExecuteQuery<int>(SlamItemContext.CommitActivity, String.Format(Queries.VerifySchemaExists, schemaName)).SingleOrDefault() > 0;
            return exists;
        }

        #region IDisposable Members

        public void Dispose()
        {
            _dataContext.Dispose();
        }

        #endregion
    }
}
